﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using ControleRepresentanteSync.Application.Wizard;
using ControleRepresentanteSync.Logic;

namespace ControleRepresentanteSync.Application.DynamicSync
{
    abstract class DynamicSyncSelectionPresenter<TViewModel, TContentViewModel, TListViewModel, TModel> : WizardPagePresenterBase<TViewModel>
        where TContentViewModel : class, IDynamicSyncContentViewModel
        where TListViewModel : IDynamicSyncListViewModel<TContentViewModel>
        where TViewModel : IDynamicSyncViewModel<TContentViewModel, TListViewModel>
    {
        protected IViewModelFactory ViewModelFactory { get; private set; }
        protected IJolitexRetriever JolitexRetriever { get; private set; }
        protected IContractsProvider ContractsProvider { get; private set; }

        private readonly WizardPageProvider m_PedidosPageProvider;

        protected DynamicSyncSelectionPresenter(TViewModel viewModel, WizardPageProvider pedidosPageProvider, IViewModelFactory viewModelFactory, IJolitexRetriever jolitexRetriever, IContractsProvider contractsProvider, IUserInterfaceService userInterfaceService) 
            : base(viewModel)
        {
            ViewModelFactory = viewModelFactory;
            JolitexRetriever = jolitexRetriever;
            ContractsProvider = contractsProvider;
            m_PedidosPageProvider = pedidosPageProvider;

            ViewModel.Title = Title;
            ViewModel.Description = Description;

            ViewModel.ContentList = viewModelFactory.CreateViewModel<TListViewModel>();
            viewModel.ContentList.IsShowIsCheckedColumn = true;

            string errors;
            IEnumerable<TModel> models = GetModels(out errors);

            if (!String.IsNullOrEmpty(errors))
            {
                userInterfaceService.ShowMessage("Erro carregando os seguintes arquivos: " + errors + "." + Environment.NewLine + "Verifique se os arquivos são válidos e não estão abertos.", "Erro", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            foreach (TModel model in models)
            {
                TContentViewModel contentViewModel = viewModelFactory.CreateViewModel<TContentViewModel>();
                contentViewModel.IsCheckedChanged += ContentViewModelIsCheckedChanged;
                CreateContentPresenter(contentViewModel, model);
                ViewModel.ContentList.Contents.Add(contentViewModel);
            }

            ViewModel.ContentList.IsAllCheckedChanged += ContentListIsAllCheckedChanged;

            UpdateIsValid();
        }

        protected abstract string Description { get; }
        protected abstract string Title { get; }
        protected abstract void CreateContentPresenter(TContentViewModel contentViewModel, TModel model);
        protected abstract IEnumerable<TModel> GetModels(out string errors);

        private void ContentListIsAllCheckedChanged(object sender, EventArgs e)
        {
            bool isAllChecked = ViewModel.ContentList.IsAllChecked;
            foreach (TContentViewModel contentViewModel in ViewModel.ContentList.Contents)
            {
                contentViewModel.IsChecked = isAllChecked;
            }
        }

        protected IEnumerable<TItem> GetSatelliteItems<TItem, TContract>(ref List<TItem> cache, Func<IContractsProvider, IEnumerable<TContract>> getContracts, Action<TItem, TContract> createItemPresenter)
            where TItem : IViewModel
        {
            if (cache == null)
            {
                cache = new List<TItem>();
                foreach (TContract contract in getContracts(ContractsProvider))
                {
                    TItem item = ViewModelFactory.CreateViewModel<TItem>();
                    createItemPresenter(item, contract);
                    cache.Add(item);
                }
            }
            return cache;
        }


        private void UpdateIsValid()
        {
            ViewModel.IsValid = ViewModel.ContentList.Contents.Any(x => x.IsChecked);
        }

        private void ContentViewModelIsCheckedChanged(object sender, EventArgs e)
        {
            TContentViewModel contentViewModel = (TContentViewModel)sender;
            if (contentViewModel.IsChecked)
            {
                m_PedidosPageProvider.AddPage(contentViewModel);
            }
            else
            {
                m_PedidosPageProvider.RemovePage(contentViewModel);
            }
            UpdateIsValid();
        }

        protected sealed override bool TryApply()
        {
            return true;
        }

        protected static void FireOnClose<T>(IEnumerable<T> items)
            where T : IViewModel
        {
            if (items != null)
            {
                foreach (IViewModel item in items)
                {
                    item.FireOnClose();
                }
            }
        }

        public override void Dispose()
        {
            base.Dispose();

            ViewModel.ContentList.IsAllCheckedChanged -= ContentListIsAllCheckedChanged;

            foreach (TContentViewModel contentViewModel in ViewModel.ContentList.Contents)
            {
                contentViewModel.IsCheckedChanged -= ContentViewModelIsCheckedChanged;
                contentViewModel.FireOnClose();
            }
        }
    }
}
